// Text of project Basic Serial written on 3/8/96 at 12:48
// Beginning of text file Project Data
// Copyright © 1994-1995 Apple Computer, Inc. All rights reserved

constant kAction_Connect := 'connect;
constant kAction_Listen := 'listen;

constant kState_Disconnected := 0;	// ready-to-go (default state)
constant kState_Listen := 1;		// preparation for (asynchronous) listen
constant kState_Listening := 2;		// in-process of (asynchronous) listen
constant kState_Connect := 3;		// preparation for (asynchronous) connect
constant kState_Connecting := 4;	// in-process of (asynchronous) connect
constant kState_Connected := 5;		// connected (requires disconnect)
constant kState_Disconnecting := 6;	// in-process of (asynchronous) disconnect

constant kMessage_Disconnected := "Ready to connectÉ";
constant kMessage_Listening := "Waiting for connection...";
constant kMessage_Connecting := "Connecting...";
constant kMessage_Connected := "Connected, awaiting disconnect...";
constant kMessage_Disconnecting := "Disconnecting, please wait...";
constant kMessage_ConnectFailed := "Connection not established; no response.";
constant kMessage_BufferOverrun := "The communications data buffer was overrun and has been reset.";
constant kMessage_Timeout := "The connection seems to have timed out.";
constant kMessage_PortInUse := "Another application seems to be using the communications port.";
constant kMessage_PortDoesNotExist := "The requested communications port does not exist.";
constant kMessage_OutputTooFast := "Synchronous outputs are occuring too quickly; some data was not output.";
// End of text file Project Data
// Beginning of file protoDisconnectSlip

// Before Script for "_userproto000"
// Copyright © 1994-1995 Apple Computer, Inc. All rights reserved.


_userproto000 :=
    {viewBounds: {left: 0, top: 0, right: 108, bottom: 44},
     viewJustify: 80,
     ReorientToScreen: ROM_DefRotateFunc,
     _proto: @179
    };

_view000 :=
    {viewBounds: {left: 8, top: 8, right: 104, bottom: 40},
     viewJustify: 2,
     text:
       "Disconnecting...
       Please Wait...",
     _proto: @218
    };
AddStepForm(_userproto000, _view000);




constant |layout_protoDisconnectSlip| := _userproto000;
// End of file protoDisconnectSlip
// Beginning of file Basic Serial.t

// Before Script for "vMainApp"
// Copyright © 1994-1995 Apple Computer, Inc. All rights reserved.


vMainApp :=
    {
     viewSetupDoneScript:
       func()
       begin
       	:MSetEndPointState(fEndPointState);		// do NOT change the endpoint state -- just update any views that depend on it
       	if fEndPointState = kState_Disconnected then
       		:MMessage(kMessage_Disconnected);
       	else
       		:MMessage("");
       end,
     MMessage:
       func(message)		// this routine can be called regardless of the value of SELF
       begin
       	local appBaseView := GetRoot().(kAppSymbol);
       	
       	if call kViewIsOpenFunc with (appBaseView) then
       		begin	
       			SetValue(appBaseView.vMessage, 'text, Clone(message));
       			RefreshViews();
       		end
       end,
     viewFormat: 83951953,
     viewQuitScript:
       func()
       begin
       	:MDisconnect();
       	RemoveSlot(GetRoot().(kAppSymbol), 'fEndPoint);
       end,
     MConnect:
       func(connectAction)
       begin
       	if fEndPointState <> kState_Disconnected then
       		return;
       	
       	fEndPoint.fConnectAction := connectAction;
       	fEndPoint.fQuiet := nil;
       	
       	if connectAction = kAction_Listen then
       		:MSetEndPointState(kState_Listen);
       	else if connectAction = kAction_Connect then
       		:MSetEndPointState(kState_Connect);
       	else
       		return;
       	
       	fEndPoint:MConnectAction();
       end,
     MDisconnectCompProc:
       func(options, result)	// SELF is the endpoint frame
       begin
       	try
       		:UnBind(nil)
       	onexception |evt.ex.comm| do
       		nil;
       	
       	try
       		:Dispose()
       	onexception |evt.ex.comm| do
       		nil;
       	
       	if fDisconnectSlip then begin
       			fDisconnectSlip:Close();
       			fDisconnectSlip := nil;
       		end;
       	
       	:MMessage(kMessage_Disconnected);
       	:MSetEndPointState(kState_Disconnected);
       	
       	if fPowerOffState then
       		begin
       			fPowerOffState := nil;
       			PowerOffResume(kAppSymbol);
       		end;
       	UnRegPowerOff(kAppSymbol);
       end,
     MShowSerialInfo:
       DefConst('kSerialInfoOptions,
       		[
       			{	label:		kCMOSerialChipSpec,
       				type:		'option,
       				opCode:		opGetCurrent,
       				result:		nil,
       				form:		'template,
       				data:	{
       					arglist:	[
       						0,					// chip location
       						0,					// features supported by this chip
       						0,					// output signals supported by chip
       						0,					// input signals supported by chip
       						0,					// parity supported
       						0,					// data and stop bits supported
       						0,					// serial chip type
       						nil,				// chip in use
       						0,					// reserved
       						0,					// reserved
       						0,					// PCMCIA card CIS manufacturer ID
       						0,	],				// PCMCIA card CIS manufacturer ID info
       					typelist:	['struct,
       						'ulong,				// fHWLoc
       						'ulong,				// fSerFeatures
       						'byte,				// fSerOutSupported
       						'byte,				// fSerInSupported
       						'byte,				// fParitySupport
       						'byte,				// fDataStopBitSupport
       						'byte,				// fUARTType
       						'boolean,			// fChipNotInUse
       						'byte,				// reserved
       						'byte,				// reserved
       						'short,				// fCIS_ManFID
       						'short,	],	},	},	// fCIS_ManFIDInfo
       		]);
       
       func()
       begin
       	if fEndPointState <> kState_Connected then
       		return :MNotify("Not connected.");
       	
       	local option := fEndPoint:Option(kSerialInfoOptions, nil);
       	if not option then
       		return;
       	
       	local result, message := "";
       
       	if (result := option[0].result) <> nil then
       		message := message & "Get serial chip info failed: (" & NumberStr(result) & ")" & unicodeCR;
       	else
       		begin
       			local serialChipType := option[0].data.arglist[6];
       			message := message & "Serial Chip: " &
       						(	 if serialChipType = 0x00 then "8250"
       						else if serialChipType = 0x01 then "16450"
       						else if serialChipType = 0x02 then "16550"
       						else if serialChipType = 0x20 then "8530"
       						else if serialChipType = 0x21 then "6850"
       						else if serialChipType = 0x22 then "6402"
       						else if serialChipType = 0x23 then "Reserved"
       						else "Unknown"	) & " UART" & unicodeCR;
       		end;
       	
       	:MMessage(message);
       end,
     fEndPointOptions:
       nil		// see MBuildConfigOptions & MConnectAction for more info
       ,
     MDisconnectAction:
       func(fromState)		// SELF is the endpoint frame
       begin
       	try
       		:Cancel(nil)
       	onexception |evt.ex.comm| do
       		nil;
       	
       	if fromState = kState_Connected then
       		try
       			:Disconnect(nil, {	async:				true,
       								// reqTimeout:		3600,
       								completionScript:	func(ep, options, result)
       													ep:MDisconnectCompProc(options, result),	})
       		onexception |evt.ex.comm| do
       			:MDisconnectCompProc(nil, CurrentException().error);
       	else
       		:MDisconnectCompProc(nil, nil);
       end,
     MBuildConfigOptions:
       func()		// SELF can be any frame that inherits to the app base view
       begin
       	local options :=
       		[
       			{	label:		kCMSAsyncSerial,
       				type:		'service,
       				opCode:		opSetRequired,
       				result:		nil,	},
       			
       			{	label:		kCMOSerialHWChipLoc,
       				type:		'option,
       				opCode:		opSetRequired,
       				result:		nil,
       				form:		'template,
       				data:	{
       					argList: [
       						vPort.clusterValue,		// kHWLocExternalSerial, kHWLocBuiltInIR, kHWLocPCMCIASlot1
       						0,	],
       					typeList: ['struct,
       						['array, 'char, 4],
       						'ulong,	],	},	},
       			
       			{	label:		kCMOSerialIOParms,
       				type:		'option,
       				opCode:		opSetRequired,
       				result:		nil,
       				form:		'template,
       				data:	{
       					arglist:	[
       						k1StopBits,				// 1 stop bit
       						kNoParity,				// no parity bit
       						k8DataBits,				// 8 data bits
       						k19200bps,	],			// date rate in bps
       					typelist:	['struct,
       						'long,					// stop bits
       						'long,					// parity
       						'long,					// data bits
       						'long,	],	},	},		// bps
       			
       			{	label:		kCMOInputFlowControlParms,
       				type:		'option,
       				opCode:		opSetRequired,
       				result:		nil,
       				form:		'template,
       				data:	{
       					arglist:	[
       						unicodeDC1, 			// xonChar	
       						unicodeDC3, 			// xoffChar	
       						nil, 					// useSoftFlowControl	
       						nil, 					// useHardFlowControl	
       						0, 						// not needed; returned	
       						0,	], 					// not needed; returned	
       					typelist:	['struct,
       						'char,					// XON character
       						'char,					// XOFF character
       						'boolean,				// software flow control
       						'boolean,				// hardware flow control
       						'boolean,				// hardware flow blocked
       						'boolean,	],	},	},	// software flow blocked
       			
       			{	label:		kCMOOutputFlowControlParms,
       				type:		'option,
       				opCode:		opSetRequired,
       				result:		nil,
       				form:		'template,
       				data:	{
       					arglist:	[
       						unicodeDC1, 			// xonChar	
       						unicodeDC3, 			// xoffChar	
       						nil, 					// useSoftFlowControl	
       						nil, 					// useHardFlowControl	
       						0, 						// not needed; returned	
       						0,	], 					// not needed; returned	
       					typelist:	['struct,
       						'char,					// XON character
       						'char,					// XOFF character
       						'boolean,				// software flow control
       						'boolean,				// hardware flow control
       						'boolean,				// hardware flow blocked
       						'boolean,	],	},	},	// software flow blocked
       		];
       	
       	options;
       end,
     viewBounds: {left: -2, top: -2, right: 230, bottom: 310},
     MExceptionHandler:
       func(exceptionFrame)		// SELF is the endpoint frame
       begin
       	if exceptionFrame
       	and exceptionFrame.data
       	and exceptionFrame.data <> -16005 then				// ignore -16005 (just the result of calling Cancel)
       		if exceptionFrame.data = -18003 then			// I/O buffer overrun
       			begin
       				AddDeferredCall(func(ep) ep:MResetConnection(true), [self]);
       				:MNotifyError(exceptionFrame.data);
       			end;
       		else begin										// handle all other (unexptected) exceptions by disconnecting the endpoint
       				AddDeferredCall(func(ep) ep:MDisconnect(), [self]);
       				:MNotifyError(exceptionFrame.data);
       			end;
       	
       	true;
       end,
     _proto: @157,
     MNotifyError:
       func(error)
       begin
       	if not error
       	or (fEndPoint and fEndPoint.fQuiet) then
       		return;
       	
       	if error = -10017 then
       		:MNotify(kMessage_OutputTooFast);
       	
       	else if error = -10078 then
       		:MNotify(kMessage_PortInUse);
       	
       	else if error = -16013 then
       		:MNotify(kMessage_Timeout);
       	
       	else if error = -16022 then
       		:MNotify(kMessage_PortDoesNotExist);
       	
       	else if error = -18003 then
       		:MNotify(kMessage_BufferOverrun);
       	
       	else if error = -38001 then
       		:MNotify(kMessage_ConnectFailed);
       	
       	else
       		:MNotify("An unexpected error has occured.  Error code = " & NumberStr(error));
       end,
     MResetConnection:
       func(cancel)		// SELF is the endpoint frame
       begin
       	if fEndPointState <> kState_Connected then
       		return;
       	
       	if cancel then
       		try
       			:Cancel(nil)
       		onexception |evt.ex.comm| do
       			nil;
       	
       	:SetInputSpec(fEndPointInputSpec);
       end,
     viewJustify: 80,
     title: kAppName,
     fEndPointState: kState_Disconnected,
     fEndPointOutputSpec:
       {
       	form:		'string,
       },
     MDisconnect:
       func()
       begin
       	if not fEndPoint
       	or fEndPointState <> kState_Connected
       	and fEndPointState <> kState_Connecting
       	and fEndPointState <> kState_Listening then
       		return;
       	
       	fEndPoint.fQuiet := true;		// supress user alerts and other interactions while disconnecting
       	
       	local fromState := fEndPointState;
       	:MSetEndPointState(kState_Disconnecting);
       	:MMessage(kMessage_Disconnecting);
       	
       	fEndPoint.fDisconnectSlip := BuildContext(GetLayout("protoDisconnectSlip"));
       	fEndPoint.fDisconnectSlip:Open();
       	
       	fEndPoint:MDisconnectAction(fromState);	
       end,
     fEndPoint: nil,
     fEndPointInputSpec:
       {
       	form:			'string,
       	termination:	{	endSequence:	[unicodeCR],	},
       	discardAfter:	256,
       	inputScript:	func(ep, data, terminator, options)
       					ep:MInput(data),
       },
     viewSetupFormScript:
       func()
       begin
       	// make view no bigger than the original MP
       	local b := GetAppParams();
       	viewBounds := RelBounds( b.appAreaLeft,	b.appAreaTop,
       						MIN( b.appAreaWidth, 240 ),
       						MIN( b.appAreaHeight, 336 ));
       	
       	self.fEndPoint :=	{	_proto:				protoBasicEndPoint,
       							_parent:			self,
       							exceptionHandler:	MExceptionHandler,
       							fConnectAction:		nil,
       							fConnectAddress:	nil,
       							fDisconnectSlip:	nil,
       							fPowerOffState:		nil,
       							fQuiet:				nil,	};
       end,
     MOutput:
       func(data)		// SELF can be any frame that inherits to the base app view
       begin
       	if fEndPointState = kState_Connected then
       		try
       			fEndPoint:Output(data & unicodeCR, nil, fEndPointOutputSpec)
       		onexception |evt.ex.comm| do
       			:MExceptionHandler(CurrentException());
       	else
       		:MNotify("Not connected.");
       end,
     MSetEndpointState:
       func(newState)		// this routine can be called regardless of the value of SELF
       begin
       	local appBaseView := GetRoot().(kAppSymbol);
       	
       	//	NOTE: We must be absolutely certain fEndPointState gets created/overridden in the app base view frame!
       	appBaseView.fEndPointState := newState;
       	
       	if not call kViewIsOpenFunc with (appBaseView) then
       		return;
       	
       	if appBaseView.fEndPointState = kState_Disconnected then begin
       			appBaseView.vConnect:Show();
       			appBaseView.vListen:Show();
       			appBaseView:MSetButtons("Connect", "Listen");
       		end;
       	
       	else if appBaseView.fEndPointState = kState_Listen then begin
       			appBaseView.vConnect:Hide();
       			appBaseView:MSetButtons("Listening", nil);
       		end;
       	
       	else if appBaseView.fEndPointState = kState_Listening then
       			appBaseView:MSetButtons("Stop Listening", nil);
       	
       	else if appBaseView.fEndPointState = kState_Connect then begin
       			appBaseView.vListen:Hide();
       			appBaseView:MSetButtons("Connecting", nil);
       		end;
       	
       	else if appBaseView.fEndPointState = kState_Connecting then
       			appBaseView:MSetButtons("Stop Connecting", nil);
       	
       	else if appBaseView.fEndPointState = kState_Connected then
       			appBaseView:MSetButtons("Disconnect", nil);
       	
       	else if appBaseView.fEndPointState = kState_Disconnecting then
       			appBaseView:MSetButtons("Disconnecting", nil);
       	
       	else
       			appBaseView:MSetButtons("I Am Confused", nil);
       	
       	RefreshViews();
       end,
     MInput:
       func(data)		// SELF is the endpoint frame
       begin
       	PlaySound(ROM_PlinkBeep);
       	:MMessage(data);
       end,
     MConnectCompProc:
       func(options, result)	// SELF is the endpoint frame
       begin
       	if result then
       		begin
       			:MNotifyError(result);
       			:MDisconnect();
       			return;
       		end;
       	
       	if fConnectAction = kAction_Listen then
       		try
       			:Accept(nil, nil)
       		onexception |evt.ex.comm| do
       			begin
       				:MNotifyError(CurrentException().error);
       				:MDisconnect();
       				return;
       			end;
       	
       	:MSetEndPointState(kState_Connected);
       	:MMessage(kMessage_Connected);
       	:MResetConnection(nil);
       	:MShowSerialInfo();
       end,
     MConnectAction:
       func()		// SELF is the endpoint frame
       begin
       	fEndPointOptions := :MBuildConfigOptions();
       	
       	try
       		:Instantiate(self, fEndPointOptions)
       	onexception |evt.ex.comm| do
       		begin
       			:MNotifyError(CurrentException().error);
       			:MSetEndPointState(kState_Disconnected);
       			return;
       		end;
       	
       	try
       		:Bind(nil, nil)
       	onexception |evt.ex.comm| do
       		begin
       			:MNotifyError(CurrentException().error);
       			:MSetEndPointState(kState_Disconnected);
       			:Dispose();
       			return;
       		end;
       	
       	RegPowerOff(kAppSymbol,
       				func(what, why)		// we create the closure here so as to set up SELF as the endpoint frame in the closure
       				begin
       					if what = 'okToPowerOff then
       						begin
       							if why <> 'idle									// keep the unit awake whenever we're connected
       							or fEndPointState = kState_Disconnected then	// unless the user or an application explicitly
       								return true;								// wants it to sleep
       						end;
       					
       					else if what = 'powerOff then
       						begin
       							if why <> 'idle									// if we simply must go to sleep but we're still
       							and fEndPointState <> kState_Disconnected then	// connected then begin the disconnect process
       								begin
       									fPowerOffState := 'holdYourHorses;		// set a flag to indicate we're powering down
       									:MDisconnect();
       									return 'holdYourHorses;
       								end;
       						end;
       					
       					nil;	// ALWAYS return nil here!
       				end	);
       	
       	try
       		begin
       			if fConnectAction = kAction_Listen then
       				begin
       					:MSetEndPointState(kState_Listening);
       					:MMessage(kMessage_Listening);
       					:Listen( nil,
       							{	async:				true,
       								reqTimeout:			90000,	// 90 seconds -- for DEMO purposes only
       								completionScript:	func(ep, options, result)
       													ep:MConnectCompProc(options, result)	});
       				end;
       			else if fConnectAction = kAction_Connect then
       				begin
       					:MSetEndPointState(kState_Connecting);
       					:MMessage(kMessage_Connecting);
       					:Connect( [ fConnectAddress ],
       							{	async:				true,
       								reqTimeout:			45000,	// 45 seconds -- for DEMO purposes only
       								completionScript:	func(ep, options, result)
       													ep:MConnectCompProc(options, result),	});
       				end;
       		end
       	onexception |evt.ex.comm| do
       		begin
       			:MNotifyError(CurrentException().error);
       			:MDisconnect();
       		end;
       end,
     debug: "vMainApp",
     MNotify:
       func(message)
       begin
       	GetRoot():Notify(kNotifyAlert, kAppName, message);	// no longer necessary to EnsureInternal params
       end,
     MSetButtons:
       func(connectText, listenText)
       begin
       	SetValue(vConnect, 'text, connectText);
       	if listenText then
       		SetValue(vListen, 'text, listenText);
       	else
       		SetValue(vListen, 'text, connectText);
       end
    };

_view001 :=
    {viewBounds: {left: 8, top: 16, right: 224, bottom: 32},
     text: "Messages & Received Data:",
     _proto: @218
    };
AddStepForm(vMainApp, _view001);



vMessage :=
    {viewBounds: {left: 9, top: 33, right: 223, bottom: 119},
     viewJustify: 0,
     viewFormat: 337,
     viewFont: simpleFont12,
     text: "",
     viewClickScript:
       func(unit)
       begin
       	SetValue(self, 'text, "");
       	true;
       end,
     viewFlags: 515,
     debug: "vMessage",
     _proto: @218
    };
AddStepForm(vMainApp, vMessage);
StepDeclare(vMainApp, vMessage, 'vMessage);



_view002 :=
    {viewBounds: {left: 8, top: 128, right: 168, bottom: 144},
     text: "Message To Send:",
     _proto: @218
    };
AddStepForm(vMainApp, _view002);



vInputArea :=
    {viewFlags: 64001,
     viewFormat: 12625,
     viewLineSpacing: 20,
     viewFont: 18434,
     viewBounds: {left: 9, top: 145, right: 167, bottom: 195},
     text: "This is a test!",
     debug: "vInputArea",
     viewClass: 81
    };
AddStepForm(vMainApp, vInputArea);
StepDeclare(vMainApp, vInputArea, 'vInputArea);



vConnect :=
    {
     buttonClickScript:
       func()
       begin
       	if fEndPointState = kState_Disconnected then
       		:MConnect(kAction_Connect);
       	else
       		:MDisconnect();
       end,
     viewBounds: {left: 122, top: 214, right: 222, bottom: 234},
     text: ""
     ,
     debug: "vConnect",
     _proto: @226
    };
AddStepForm(vMainApp, vConnect);
StepDeclare(vMainApp, vConnect, 'vConnect);



vListen :=
    {
     buttonClickScript:
       func()
       begin
       	if fEndPointState = kState_Disconnected then
       		:MConnect(kAction_Listen);
       	else
       		:MDisconnect();
       end,
     viewBounds: {left: 122, top: 242, right: 222, bottom: 262},
     text: ""
     ,
     debug: "vListen",
     _proto: @226
    };
AddStepForm(vMainApp, vListen);
StepDeclare(vMainApp, vListen, 'vListen);



vSend :=
    {
     buttonClickScript:
       func()
       begin
       	:MOutput(if vInputArea.text then vInputArea.text else "");
       end,
     viewBounds: {left: 178, top: 146, right: 222, bottom: 166},
     text: "Send",
     debug: "vSend",
     _proto: @226
    };
AddStepForm(vMainApp, vSend);
StepDeclare(vMainApp, vSend, 'vSend);



_view003 :=
    {viewBounds: {left: 8, top: 204, right: 112, bottom: 220},
     text: "Serial Port To Use:",
     _proto: @218
    };
AddStepForm(vMainApp, _view003);



vPort :=
    {viewBounds: {left: 16, top: 220, right: 112, bottom: 276},
     clusterValue: kHWLocExternalSerial,
     debug: "vPort",
     _proto: @203
    };
AddStepForm(vMainApp, vPort);
StepDeclare(vMainApp, vPort, 'vPort);

_view004 :=
    {buttonValue: kHWLocExternalSerial,
     viewBounds: {left: 0, top: 0, right: 96, bottom: 16},
     text: "RS422 (Port A)",
     _proto: @202
    };
AddStepForm(vPort, _view004);



_view005 :=
    {buttonValue: kHWLocBuiltInIR,
     viewBounds: {left: 0, top: 16, right: 96, bottom: 32},
     text: "IR (Port B)",
     _proto: @202
    };
AddStepForm(vPort, _view005);



_view006 :=
    {buttonValue: kHWLocPCMCIASlot1,
     viewBounds: {left: 0, top: 32, right: 96, bottom: 48},
     text: "Serial Card In Slot 1",
     _proto: @202
    };
AddStepForm(vPort, _view006);






constant |layout_Basic Serial.t| := vMainApp;
// End of file Basic Serial.t



